#include "SRNLUResult.h"
#include "UIJSONParser.h"
#include "jansson.h"
#include <iostream>

SRNLUBatchTester* SRNLUBatchTester::m_pInstance = NULL;

SRNLUResult::SRNLUResult(void)
{
}

SRNLUResult::~SRNLUResult(void)
{
}

void SRNLUResult::clearSRHyp()
{
	m_SRHyps.clear();
	m_SRHypsLinks.clear();
}

void SRNLUResult::clearNLUHyp()
{
	m_NLUHyps.clear();
	m_NLUHypsLinks.clear();
}

void SRNLUResult::clearAll()
{
	clearSRHyp();
	clearNLUHyp();
}

void SRNLUResult::addSRHyp(SRHypothesis hyp)
{
	m_SRHyps.push_back(hyp);
	m_SRHypsLinks[hyp.srSource].push_back(m_SRHyps.size()-1);
}

void SRNLUResult::addNLUHyp(NLUHypothesis hyp)
{
	m_NLUHyps.push_back(hyp);
	m_NLUHypsLinks[hyp.nluSource].push_back(m_NLUHyps.size()-1);
}
	
int SRNLUResult::getSRHypSize(void)
{
	return m_SRHyps.size();
}

int SRNLUResult::getSRHypSize(SREngineType type)
{
	if (m_SRHypsLinks.find(type) == m_SRHypsLinks.end())
		 return 0;
	return m_SRHypsLinks[type].size();
}

SRHypothesis* SRNLUResult::getSRHyp(int index)
{
	if (index < 0 || index >= getSRHypSize())
		return NULL;
	return m_SRHyps.data() + index;
}

SRHypothesis* SRNLUResult::getSRHyp(SREngineType type, int index)
{
	if (index < 0 || index >= getSRHypSize(type))
		return NULL;
	return m_SRHyps.data() + m_SRHypsLinks[type][index];
}

SRHypothesis* SRNLUResult::getSRHypByID(int hypoId)
{
	std::vector<SRHypothesis>::iterator it;
	for (it = m_SRHyps.begin(); it != m_SRHyps.end(); it++){
		if ((*it).srHypID == hypoId){
			return &(*it);
		}
	}
	return NULL;
}

int SRNLUResult::getNLUHypSize(void)
{
	return m_NLUHyps.size();
}

int SRNLUResult::getNLUHypSize(NLUEngineType type)
{
	if (m_NLUHypsLinks.find(type) == m_NLUHypsLinks.end())
		 return 0;
	return m_NLUHypsLinks[type].size();
}

NLUHypothesis* SRNLUResult::getNLUHyp(int index)
{
	if (index < 0 || index >= getNLUHypSize())
		return NULL;
	return m_NLUHyps.data()+index;
}

NLUHypothesis* SRNLUResult::getNLUHyp(NLUEngineType type, int index)
{
	if (index < 0 || index >= getNLUHypSize(type))
		return NULL;
	
	return m_NLUHyps.data() + m_NLUHypsLinks[type][index];
}

std::vector<SREngineType> SRNLUResult::getSREngines(void)
{
	std::vector<SREngineType> types;
	std::map<SREngineType, std::vector<int> >::iterator itEngines;
	for (itEngines = m_SRHypsLinks.begin(); itEngines != m_SRHypsLinks.end(); itEngines++)
		types.push_back(itEngines->first);
	return types;
}

std::vector<NLUEngineType> SRNLUResult::getNLUEngines(void)
{
	std::vector<NLUEngineType> types;
	std::map<NLUEngineType, std::vector<int> >::iterator itEngines;
	for (itEngines = m_NLUHypsLinks.begin(); itEngines != m_NLUHypsLinks.end(); itEngines++)
		types.push_back(itEngines->first);
	return types;
}

void SRNLUResult::addAllSRHyp(SRNLUResult *result)
{
	if (!result) return;
	for (int i=0; i<result->getSRHypSize(); i++)
		addSRHyp(*result->getSRHyp(i));
}

void SRNLUResult::addAllNLUHyp(SRNLUResult *result)
{
	if (!result) return;
	for (int i=0; i<result->getNLUHypSize(); i++)
		addNLUHyp(*result->getNLUHyp(i));
}

void SRNLUResult::addAllHyp(SRNLUResult *result)
{
	if (!result) return;
	addAllSRHyp(result);
	addAllNLUHyp(result);
}

std::string SRNLUResult::serializeJSON(void)
{
	std::string jsonString = "{";
	
	// serialize reference
	jsonString += m_reference.serializeJSON() + ",";

	// serialize srResult
	jsonString += "\"srresult\":[";
	std::vector<SREngineType> srEngines = getSREngines();
	int iHypID = 0;
	for (int iEngine = 0; iEngine < (int)srEngines.size(); iEngine++)
	{
		int hypNum = getSRHypSize(srEngines[iEngine]);

		jsonString += (iEngine==0) ? "{" : ",{";
		jsonString += "\"source\":\"" + getSREngineName(srEngines[iEngine]) + "\",";
		jsonString += "\"hypothesis_num\":" + toStr(hypNum) + ",";
		jsonString += "\"hypotheses\":[";

		for (int iHyp=0; iHyp<hypNum; iHyp++) 
		{
			SRHypothesis hyp = m_SRHyps[m_SRHypsLinks[srEngines[iEngine]][iHyp]];
			jsonString += (iHyp==0) ? "{" : ",{";
			jsonString += "\"id\":" + toStr(iHypID++) + ",";
			jsonString += "\"sentence\":\"" + std::string(hyp.sentence) + "\",";
			jsonString += "\"confidence\":" + toStr(hyp.sentConf) + ",";
			jsonString += "\"probability\":" + toStr(hyp.sentProb) + ",";
			jsonString += "\"lmscore\":" + toStr(hyp.sentLMScore) + ",";
			jsonString += "\"starttime\":" + toStr(hyp.sentStartTime) + ",";
			jsonString += "\"endtime\":" + toStr(hyp.sentEndTime) + ",";
			jsonString += "\"words\":[";
			for (int iWord=0; iWord<hyp.numOfWords; iWord++) 
			{
				jsonString += (iWord==0) ? "{" : ",{";
				jsonString += "\"word\":\"" + std::string(hyp.sentWords[iWord].word) + "\",";
				jsonString += "\"confidence\":" + toStr(hyp.sentWords[iWord].wordConf) + ",";
				jsonString += "\"probability\":" + toStr(hyp.sentWords[iWord].wordProb) + ",";
				jsonString += "\"lmscore\":" + toStr(hyp.sentWords[iWord].wordLMScore) + ",";
				jsonString += "\"starttime\":" + toStr(hyp.sentWords[iWord].wordStartTime) + ",";
				jsonString += "\"endtime\":" + toStr(hyp.sentWords[iWord].wordEndTime) + ",";
				jsonString += "\"slotname\":\"" + std::string(hyp.sentWords[iWord].srSlotName) + "\",";
				jsonString += "\"id\":" + toStr((int) hyp.sentWords[iWord].wordUserID) + "}";
			}
			jsonString += "]}";
		}
		jsonString += "]}";
	}

	// serialize nluResult
	int groupID = 0;
	jsonString += "],\"nluresult\":[";
	for (int iHyp=0; iHyp<(int)m_NLUHyps.size(); iHyp++)
	{
		jsonString += (iHyp==0) ? "{" : ",{";
		jsonString += "\"source\":\"" + getNLUEngineName(m_NLUHyps[iHyp].nluSource) + "\",";
		jsonString += "\"hypothesis_id\":" + toStr(m_NLUHyps[iHyp].srHypID) + ",";
		jsonString += "\"topic\":\"" + std::string(m_NLUHyps[iHyp].topic) + "\",";
		jsonString += "\"confidence\":" + toStr(m_NLUHyps[iHyp].topicConf) + ",";
		int curGroupID = -1;
		if (m_NLUHyps[iHyp].groupID >= 0){
			curGroupID = m_NLUHyps[iHyp].groupID + 10000;
		}else{
			curGroupID = groupID ++;
		}
		jsonString += "\"groupID\":" + toStr(curGroupID) + ",";
		jsonString += "\"interpretation_num\":" + toStr(m_NLUHyps[iHyp].numOfInterps) + ",";
		jsonString += "\"interpretations\":[";
		for (int iInterp=0; iInterp<m_NLUHyps[iHyp].numOfInterps; iInterp++) 
		{
			jsonString += (iInterp==0) ? "{" : ",{";
			jsonString += "\"score\":" + toStr(m_NLUHyps[iHyp].interpretations[iInterp].interpConf) + ",";
			jsonString += "\"slot_num\":" + toStr(m_NLUHyps[iHyp].interpretations[iInterp].numOfSlots) + ",";
			jsonString += "\"slots\":[";
			for (int iSlot=0; iSlot<m_NLUHyps[iHyp].interpretations[iInterp].numOfSlots; iSlot++)
			{
				jsonString += (iSlot==0) ? "{" : ",{";
				jsonString += "\"slotname\":\"" + std::string(m_NLUHyps[iHyp].interpretations[iInterp].slots[iSlot].slotName) + "\",";
				jsonString += "\"slotvalue\":\"" + std::string(m_NLUHyps[iHyp].interpretations[iInterp].slots[iSlot].slotValue) + "\",";
				jsonString += "\"probability\":" + toStr(m_NLUHyps[iHyp].interpretations[iInterp].slots[iSlot].slotConf) + ",";
				jsonString += "\"startposition\":" + toStr(m_NLUHyps[iHyp].interpretations[iInterp].slots[iSlot].slotStartPosition) + ",";
				jsonString += "\"endposition\":" + toStr(m_NLUHyps[iHyp].interpretations[iInterp].slots[iSlot].slotEndPosition) + "}";
			}
			jsonString += "]}";
		}
		jsonString += "]}";
	}
	jsonString += "]}";
	return jsonString;
}

std::string SRNLUResult::serializeVoConHRL(std::vector<std::string> refFields)
{
	// serialize reference
	std::string ref = m_reference.serializeVoConHRL(refFields);
	ref += "#" + toStr(getSRHypSize()) + "#RESULTTYPE_FINAL\n";
	
	// serialize srResult
	std::string srResult = "";
	std::vector<SREngineType> srEngines = getSREngines();
	int iHypID = 0;
	for (int iEngine = 0; iEngine < (int)srEngines.size(); iEngine++)
	{
		int hypNum = getSRHypSize(srEngines[iEngine]);
		std::string engineName = getSREngineName(srEngines[iEngine]);

		for (int iHyp=0; iHyp<hypNum; iHyp++) 
		{
			SRHypothesis hyp = m_SRHyps[m_SRHypsLinks[srEngines[iEngine]][iHyp]];

			srResult += "hyp#" + toStr(iHypID++) + "#";
			srResult += engineName + "#";
			srResult += replaceAll(hyp.sentence, " ", ";") + "#";
			srResult += toStr(int(hyp.sentConf * 10000)) + "#";
			srResult += toStr(int(hyp.sentProb * 10000)) + "#";
			srResult += toStr(int(hyp.sentLMScore * 10000)) + "#";

			std::string wordConf    = "";
			std::string wordLMScore = "";
			for (int iWord=0; iWord<hyp.numOfWords; iWord++) 
			{
				wordConf += (iWord==0) ? "" : ";";
				wordConf += toStr(int(hyp.sentWords[iWord].wordConf * 10000));
				wordLMScore += (iWord==0) ? "" : ";";
				wordLMScore += toStr(int(hyp.sentWords[iWord].wordLMScore * 10000));
			}
			srResult += wordConf + "#";
			srResult += wordLMScore + "\n";
		}
	}

	// serialize nluResult
	std::string nluResult = "";
	for (int iHyp=0; iHyp<(int)m_NLUHyps.size(); iHyp++)
	{
		nluResult += "classres#" + getNLUEngineName(m_NLUHyps[iHyp].nluSource) + "#";
		nluResult += std::string(m_NLUHyps[iHyp].topic) + "#";
		nluResult += toStr(m_NLUHyps[iHyp].topicConf) + "\n";

		for (int iInterp=0; iInterp<m_NLUHyps[iHyp].numOfInterps; iInterp++) 
		{
			nluResult += "interpretation#" + toStr(iInterp) + "#";
			nluResult += toStr(m_NLUHyps[iHyp].interpretations[iInterp].interpConf) + "#";

			std::string slotNames = "";
			std::string slotValues = "";
			std::string slotConfs = "";
			for (int iSlot=0; iSlot<m_NLUHyps[iHyp].interpretations[iInterp].numOfSlots; iSlot++)
			{
				slotNames	+= (iSlot==0) ? "" : ";";
				slotValues	+= (iSlot==0) ? "" : ";";
				slotConfs	+= (iSlot==0) ? "" : ";";

				slotNames	+= std::string(m_NLUHyps[iHyp].interpretations[iInterp].slots[iSlot].slotName);
				slotValues	+= std::string(m_NLUHyps[iHyp].interpretations[iInterp].slots[iSlot].slotValue);
				slotConfs	+= toStr(m_NLUHyps[iHyp].interpretations[iInterp].slots[iSlot].slotConf);
			}
			nluResult += slotNames + "#" + slotValues + "#" + slotConfs + "\n";
		}
	}
	return ref + nluResult + srResult;
}

/*
void SRNLUResult::deserializeJSON(std::string jsonString)
{
	std::string strVal;
	int iVal;
	double dVal;
	bool bVal;

	m_SRHyps.clear();
	m_SRHypsLinks.clear();
	m_NLUHyps.clear();
	m_NLUHypsLinks.clear();

	for (int iEngine=0; iEngine < UIJSONParser::getArraySize(jsonString, "srresult"); iEngine++) 
	{
		std::string engineKeyPrefix = "srresult[" + toStr(iEngine) + "]";

		SREngineType src;
		if (UIJSONParser::getString(jsonString, engineKeyPrefix + ".source", strVal))
			src = getSREngineType(strVal);

		for (int iHyp=0; iHyp < UIJSONParser::getArraySize(jsonString, engineKeyPrefix + ".hypotheses"); iHyp++) 
		{
			std::string hypKeyPrefix = engineKeyPrefix + ".hypotheses[" + toStr(iHyp) + "]";
			SRHypothesis hyp;
			hyp.srSource = src;
			if (UIJSONParser::getInt(jsonString, hypKeyPrefix + ".id", iVal))
				hyp.srHypID = iVal;
			if (UIJSONParser::getString(jsonString, hypKeyPrefix + ".sentence", strVal))
				strcpy(hyp.sentence, strVal.c_str());
			if (UIJSONParser::getDouble(jsonString, hypKeyPrefix + ".confidence", dVal))
				hyp.sentConf = dVal;
			if (UIJSONParser::getDouble(jsonString, hypKeyPrefix + ".probability", dVal))
				hyp.sentProb = dVal;
			if (UIJSONParser::getDouble(jsonString, hypKeyPrefix + ".lmscore", dVal))
				hyp.sentLMScore = dVal;
			if (UIJSONParser::getDouble(jsonString, hypKeyPrefix + ".starttime", dVal))
				hyp.sentStartTime = dVal;
			if (UIJSONParser::getDouble(jsonString, hypKeyPrefix + ".endtime", dVal))
				hyp.sentEndTime = dVal;
			hyp.numOfWords = UIJSONParser::getArraySize(jsonString, hypKeyPrefix + ".words");

			for (int iWord = 0; iWord < hyp.numOfWords; iWord++) {
				std::string wordKeyPrefix = hypKeyPrefix + ".words[" + toStr(iWord) + "]";
				if (UIJSONParser::getString(jsonString, wordKeyPrefix + ".word", strVal))
					strcpy(hyp.sentWords[iWord].word, strVal.c_str());
				if (UIJSONParser::getDouble(jsonString, wordKeyPrefix + ".confidence", dVal))
					hyp.sentWords[iWord].wordConf = dVal;
				if (UIJSONParser::getDouble(jsonString, wordKeyPrefix + ".probability", dVal))
					hyp.sentWords[iWord].wordProb = dVal;
				if (UIJSONParser::getDouble(jsonString, wordKeyPrefix + ".lmscore", dVal))
					hyp.sentWords[iWord].wordLMScore = dVal;
				if (UIJSONParser::getInt(jsonString, wordKeyPrefix + ".starttime", iVal))
					hyp.sentWords[iWord].wordStartTime = iVal;
				if (UIJSONParser::getInt(jsonString, wordKeyPrefix + ".endtime", iVal))
					hyp.sentWords[iWord].wordEndTime = iVal;
			
				if (UIJSONParser::getString(jsonString, wordKeyPrefix + ".slotname", strVal) && !strVal.empty()) {
					hyp.sentWords[iWord].isSRSlot = true;
					strcpy(hyp.sentWords[iWord].srSlotName, strVal.c_str());
				}
				else {
					hyp.sentWords[iWord].isSRSlot = false;
				}
				if (UIJSONParser::getInt(jsonString, wordKeyPrefix + ".id", iVal))
					hyp.sentWords[iWord].wordUserID = iVal;
			}
			addSRHyp(hyp);
		}
	}

	for (int iHyp=0; iHyp < UIJSONParser::getArraySize(jsonString, "nluresult"); iHyp++) 
	{
		std::string keyPrefix = "nluresult[" + toStr(iHyp) + "]";
		NLUHypothesis hyp;
		if (UIJSONParser::getString(jsonString, keyPrefix + ".source", strVal))
			hyp.nluSource = getNLUEngineType(strVal);
		if (UIJSONParser::getInt(jsonString, keyPrefix + ".hypothesis_id", iVal))
			hyp.srHypID = iVal;
		if (UIJSONParser::getString(jsonString, keyPrefix + ".topic", strVal))
			strcpy(hyp.topic, strVal.c_str());
		if (UIJSONParser::getDouble(jsonString, keyPrefix + ".confidence", dVal))
			hyp.topicConf = dVal;
		hyp.numOfInterps = UIJSONParser::getArraySize(jsonString, keyPrefix + ".interpretations");

		for (int iInterp = 0; iInterp < hyp.numOfInterps; iInterp++) {
			std::string interpKeyPrefix = keyPrefix + ".interpretations[" + toStr(iInterp) + "]";
			if (UIJSONParser::getDouble(jsonString, interpKeyPrefix + ".score", dVal))
				hyp.interpretations[iInterp].interpConf = dVal;
			hyp.interpretations[iInterp].numOfSlots = UIJSONParser::getArraySize(jsonString, interpKeyPrefix + ".slots");
			for (int iSlot = 0; iSlot < hyp.interpretations[iInterp].numOfSlots; iSlot++) 
			{
				std::string slotKeyPrefix = interpKeyPrefix + ".slots[" + toStr(iSlot) + "]";
				if (UIJSONParser::getString(jsonString, slotKeyPrefix + ".slotname", strVal))
					strcpy(hyp.interpretations[iInterp].slots[iSlot].slotName, strVal.c_str());
				if (UIJSONParser::getString(jsonString, slotKeyPrefix + ".slotvalue", strVal))
					strcpy(hyp.interpretations[iInterp].slots[iSlot].slotValue, strVal.c_str());
				if (UIJSONParser::getDouble(jsonString, slotKeyPrefix + ".probability", dVal))
					hyp.interpretations[iInterp].slots[iSlot].slotConf = dVal;
				if (UIJSONParser::getInt(jsonString, slotKeyPrefix + ".startposition", iVal))
					hyp.interpretations[iInterp].slots[iSlot].slotStartPosition = iVal;
				if (UIJSONParser::getInt(jsonString, slotKeyPrefix + ".endposition", iVal))
					hyp.interpretations[iInterp].slots[iSlot].slotEndPosition = iVal;
			}
		}
		addNLUHyp(hyp);
	}
}
*/

void SRNLUResult::deserializeJSON(std::string jsonString)
{
	std::string strVal;
//	int iVal;
//	double dVal;
//	bool bVal;

	m_SRHyps.clear();
	m_SRHypsLinks.clear();
	m_NLUHyps.clear();
	m_NLUHypsLinks.clear();
	m_reference.clear();

	json_error_t * json_error = new json_error_t();
	json_t *root = json_loads(jsonString.c_str(), JSON_DECODE_ANY, json_error);
	if (root == NULL)	return;

	json_t *reference = json_object_get(root, "reference");
	if (reference != NULL) {
		json_t *node = json_object_get(reference, "audio");
		if (node != NULL) {
			if (json_is_string(node))
				m_reference.audioSource = json_string_value(node);
			free(node);
		}

		node = json_object_get(reference, "trans");
		if (node != NULL) {
			if (json_is_string(node))
				m_reference.refSent = json_string_value(node);
			free(node);
		}

		node = json_object_get(reference, "topic");
		if (node != NULL) {
			if (json_is_string(node)) 
				m_reference.refTopic = json_string_value(node);
			free(node);
		}

		node = json_object_get(reference, "slots");
		if (node != NULL) {
			if (json_is_array(node)) {
				for (int iSlot=0; iSlot < (int)json_array_size(node); iSlot++)
				{
					json_t *slotnode = json_array_get(node, iSlot);
					json_t *tmpsnode;
					
					std::string slotName  = "";
					std::string slotValue = "";
					tmpsnode = json_object_get(slotnode, "slotname");
					if (tmpsnode != NULL) {
						if (json_is_string(tmpsnode)) {
							slotName = json_string_value(tmpsnode);
						}
						free(tmpsnode);
					}
					tmpsnode = json_object_get(slotnode, "slotvalue");
					if (tmpsnode != NULL) {
						if (json_is_string(tmpsnode)) {
							slotValue = json_string_value(tmpsnode);
						}
						free(tmpsnode);
					}
					if (slotName.length() > 0 && slotValue.length() > 0)
						m_reference.refSlots[slotName] = slotValue;
					free(slotnode);
				}
			}
			free(node);
		}

		node = json_object_get(reference, "otherFields");
		if (node != NULL) {
			if (json_is_object(node)) {
				void *iter = json_object_iter(node);
				while (iter)
				{
					std::string key = json_object_iter_key(iter);
					json_t* value = json_object_iter_value(iter);
					if (json_is_string(value)) {
						m_reference.refOtherFields[key] = json_string_value(value);
					}
					iter = json_object_iter_next(node, iter);
				}
			}
			free(node);
		}
		free(reference);
	}

	json_t *srresult = json_object_get(root, "srresult");
	if (srresult != NULL) {
		if (!json_is_array(srresult)) {
			free(srresult);
			return;
		}

		for (int iEngine=0; iEngine < (int)json_array_size(srresult); iEngine++)
		{
			json_t *resultnode = json_array_get(srresult, iEngine);

			SREngineType src = SR_ENGINE_UNKNOWN;
			json_t *node = json_object_get(resultnode, "source");
			if (node != NULL) {
				if (json_is_string(node)) {
					src = getSREngineType(json_string_value(node));
				}
				free(node);
			}

			node = json_object_get(resultnode, "hypotheses");
			if (node == NULL) {
				free(resultnode);
				continue;
			}

			if (!json_is_array(node)) {
				free(node);
				free(resultnode);
				continue;
			}

			for (int iHyp=0; iHyp < (int)json_array_size(node); iHyp++)
			{
				json_t *hypnode = json_array_get(node, iHyp);

				SRHypothesis hyp;
				hyp.srSource = src;
			
				json_t *tmpnode = json_object_get(hypnode, "id");
				if (tmpnode != NULL) {
					if (json_is_integer(tmpnode))
						hyp.srHypID = json_integer_value(tmpnode);
					free(tmpnode);
				}

				tmpnode = json_object_get(hypnode, "sentence");
				if (tmpnode != NULL) {
					if (json_is_string(tmpnode))
						strcpy(hyp.sentence, json_string_value(tmpnode));
					free(tmpnode);
				}

				tmpnode = json_object_get(hypnode, "confidence");
				if (tmpnode != NULL) {
					if (json_is_real(tmpnode))
						hyp.sentConf = json_real_value(tmpnode);
					free(tmpnode);
				}

				tmpnode = json_object_get(hypnode, "probability");
				if (tmpnode != NULL) {
					if (json_is_real(tmpnode))
						hyp.sentProb = json_real_value(tmpnode);
					free(tmpnode);
				}

				tmpnode = json_object_get(hypnode, "lmscore");
				if (tmpnode != NULL) {
					if (json_is_real(tmpnode))
						hyp.sentLMScore = json_real_value(tmpnode);
					free(tmpnode);
				}

				tmpnode = json_object_get(hypnode, "starttime");
				if (tmpnode != NULL) {
					if (json_is_integer(tmpnode))
						hyp.sentStartTime = json_integer_value(tmpnode);
					free(tmpnode);
				}

				tmpnode = json_object_get(hypnode, "endtime");
				if (tmpnode != NULL) {
					if (json_is_integer(tmpnode))
						hyp.sentEndTime = json_integer_value(tmpnode);
					free(tmpnode);
				}

				tmpnode = json_object_get(hypnode, "words");
				if (tmpnode != NULL) {
					if (json_is_array(tmpnode)) {
						hyp.numOfWords = json_array_size(tmpnode);
						for (int iWord = 0; iWord < hyp.numOfWords; iWord++)
						{
							json_t* wordnode = json_array_get(tmpnode, iWord);

							json_t* tmpwnode;
							tmpwnode = json_object_get(wordnode, "word");
							if (tmpwnode != NULL) {
								if (json_is_string(tmpwnode))
									strcpy(hyp.sentWords[iWord].word, json_string_value(tmpwnode));
								free(tmpwnode);
							}
							tmpwnode = json_object_get(wordnode, "confidence");
							if (tmpwnode != NULL) {
								if (json_is_real(tmpwnode))
									hyp.sentWords[iWord].wordConf = json_real_value(tmpwnode);
								free(tmpwnode);
							}
							tmpwnode = json_object_get(wordnode, "probability");
							if (tmpwnode != NULL) {
								if (json_is_real(tmpwnode))
									hyp.sentWords[iWord].wordProb = json_real_value(tmpwnode);
								free(tmpwnode);
							}
							tmpwnode = json_object_get(wordnode, "lmscore");
							if (tmpwnode != NULL) {
								if (json_is_real(tmpwnode))
									hyp.sentWords[iWord].wordLMScore = json_real_value(tmpwnode);
								free(tmpwnode);
							}
							tmpwnode = json_object_get(wordnode, "starttime");
							if (tmpwnode != NULL) {
								if (json_is_integer(tmpwnode))
									hyp.sentWords[iWord].wordStartTime = json_integer_value(tmpwnode);
								free(tmpwnode);
							}
							tmpwnode = json_object_get(wordnode, "endtime");
							if (tmpwnode != NULL) {
								if (json_is_integer(tmpwnode))
									hyp.sentWords[iWord].wordEndTime = json_integer_value(tmpwnode);
								free(tmpwnode);
							}

							hyp.sentWords[iWord].isSRSlot = false;
							tmpwnode = json_object_get(wordnode, "slotname");
							if (tmpwnode != NULL) {
								if (json_is_string(tmpwnode)) {
									if (strlen(json_string_value(tmpwnode)) > 0) {
										hyp.sentWords[iWord].isSRSlot = true;
										strcpy(hyp.sentWords[iWord].srSlotName, json_string_value(tmpwnode));
									}
								}
								free(tmpwnode);
							}

							tmpwnode = json_object_get(wordnode, "id");
							if (tmpwnode != NULL) {
								if (json_is_integer(tmpwnode))
									hyp.sentWords[iWord].wordUserID = json_integer_value(tmpwnode);
								free(tmpwnode);
							}
							free(wordnode);
						}
					}
					free(tmpnode);
				}
				addSRHyp(hyp);
				free(hypnode);
			}
			free(node);
			free(resultnode);
		}
		free(srresult);
	}

	json_t *nluresult = json_object_get(root, "nluresult");
	if (nluresult != NULL) {
		if (!json_is_array(nluresult)) {
			free(nluresult);
			return;
		}

		for (int iHyp=0; iHyp < (int)json_array_size(nluresult); iHyp++)
		{
			json_t *resultnode = json_array_get(nluresult, iHyp);
			NLUHypothesis hyp;
			
			json_t *node = json_object_get(resultnode, "source");
			if (node != NULL) {
				if (json_is_string(node)) {
					hyp.nluSource = getNLUEngineType(json_string_value(node));
				}
				free(node);
			}
			node = json_object_get(resultnode, "hypothesis_id");
			if (node != NULL) {
				if (json_is_integer(node)) {
					hyp.srHypID = json_integer_value(node);
				}
				free(node);
			}
			node = json_object_get(resultnode, "topic");
			if (node != NULL) {
				if (json_is_string(node)) {
					strcpy(hyp.topic, json_string_value(node));
				}
				free(node);
			}
			node = json_object_get(resultnode, "confidence");
			if (node != NULL) {
				if (json_is_real(node)) {
					hyp.topicConf = json_real_value(node);
				}
				free(node);
			}
			node = json_object_get(resultnode, "groupID");
			if (node != NULL) {
				if (json_is_integer(node)) {
					hyp.groupID = json_integer_value(node);
				}
				free(node);
			}
			node = json_object_get(resultnode, "interpretations");
			if (node == NULL) {
				addNLUHyp(hyp);
				free(resultnode);
				continue;
			}
			if (!json_is_array(node)) {
				addNLUHyp(hyp);
				free(node);
				free(resultnode);
				continue;
			}
			hyp.numOfInterps = json_array_size(node);

			for (int iInterp = 0; iInterp < hyp.numOfInterps; iInterp++)
			{
				json_t *interpnode = json_array_get(node, iInterp);

				json_t *tmpnode = json_object_get(interpnode, "score");
				if (tmpnode != NULL) {
					if (json_is_real(tmpnode)) {
						hyp.interpretations[iInterp].interpConf = json_real_value(tmpnode);
					}
					free(tmpnode);
				}

				tmpnode = json_object_get(interpnode, "slots");
				if (tmpnode == NULL) {
					free(interpnode);
					continue;
				}
				if (!json_is_array(tmpnode)) {
					free(tmpnode);
					free(interpnode);
					continue;
				}
				hyp.interpretations[iInterp].numOfSlots = json_array_size(tmpnode);

				for (int iSlot = 0; iSlot < hyp.interpretations[iInterp].numOfSlots; iSlot++) 
				{
					json_t *slotnode = json_array_get(tmpnode, iSlot);
					json_t *tmpsnode;
					
					tmpsnode = json_object_get(slotnode, "slotname");
					if (tmpsnode != NULL) {
						if (json_is_string(tmpsnode)) {
							strcpy(hyp.interpretations[iInterp].slots[iSlot].slotName, json_string_value(tmpsnode));
						}
						free(tmpsnode);
					}
					tmpsnode = json_object_get(slotnode, "slotvalue");
					if (tmpsnode != NULL) {
						if (json_is_string(tmpsnode)) {
							strcpy(hyp.interpretations[iInterp].slots[iSlot].slotValue, json_string_value(tmpsnode));
						}
						free(tmpsnode);
					}
					tmpsnode = json_object_get(slotnode, "probability");
					if (tmpsnode != NULL) {
						if (json_is_real(tmpsnode)) {
							hyp.interpretations[iInterp].slots[iSlot].slotConf = json_real_value(tmpsnode);
						}
						free(tmpsnode);
					}
					tmpsnode = json_object_get(slotnode, "startposition");
					if (tmpsnode != NULL) {
						if (json_is_integer(tmpsnode)) {
							hyp.interpretations[iInterp].slots[iSlot].slotStartPosition = json_integer_value(tmpsnode);
						}
						free(tmpsnode);
					}
					tmpsnode = json_object_get(slotnode, "endposition");
					if (tmpsnode != NULL) {
						if (json_is_integer(tmpsnode)) {
							hyp.interpretations[iInterp].slots[iSlot].slotEndPosition = json_integer_value(tmpsnode);
						}
						free(tmpsnode);
					}
					free(slotnode);
				}
				free(tmpnode);
				free(interpnode);
			}
			free(node);
			free(resultnode);
			addNLUHyp(hyp);
		}
		free(nluresult);
	}
	free(root);
}

void SRNLUResult::printOut()
{
	std::cout << "-----------------------------------------------------" << std::endl;
	int srNum = this->getSRHypSize();
	for(int i=0; i<srNum; i++){
		SRHypothesis* srHypo = this->getSRHyp(i);
		std::cout << "SR Hypothesis " << i << std::endl;
		std::cout << srHypo->srHypID << " " << srHypo->srSource << " " << srHypo->sentence << "(" << srHypo->sentConf << ")" << std::endl;
	}
	std::cout << "-----------------------------------------------------" << std::endl;
	int nluNum = this->getNLUHypSize();
	for(int i=0; i<nluNum; i++){
		NLUHypothesis* nluHypo = this->getNLUHyp(i);
		std::cout << "NLU Hypothesis " << i << std::endl;
		std::cout << nluHypo->srHypID << " " << nluHypo->nluSource << " " << nluHypo->topic << "(" << nluHypo->topicConf << ")" << std::endl;
		int interNum = nluHypo->numOfInterps;
		for(int j=0; j< interNum; j++){
			NLUInterp curInter = nluHypo->interpretations[j];
			std::cout << "interpretation " << j << " (" << curInter.interpConf << "): ";
			int slotNum = curInter.numOfSlots;
			for(int k=0; k<slotNum; k++){
				NLUSlot curSlot = curInter.slots[k];
				std::cout << curSlot.slotName << "=" << curSlot.slotValue << " (" << curSlot.slotConf << "); ";
			}
			std::cout << std::endl;
		}
	}
	std::cout << "-----------------------------------------------------" << std::endl;
}

SRNLUReference::SRNLUReference(void) 
{
	clear();
}

SRNLUReference::~SRNLUReference(void)
{
}

std::string SRNLUReference::serializeVoConHRL(std::vector<std::string> refFields)
{
	// serialize reference
	std::string ref = "ref";

	std::string refSlotNames = "";
	std::string refSlotValues = "";
	for (std::map<std::string, std::string>::iterator iteSlot = refSlots.begin(); iteSlot != refSlots.end(); iteSlot++) 
	{
		refSlotNames	+= (refSlotNames.length() == 0) ? "" : ";";
		refSlotValues	+= (refSlotValues.length() == 0) ? "" : ";";
		refSlotNames	+= iteSlot->first;
		refSlotValues	+= iteSlot->second;
	}

	for (int i=0; i<(int)refFields.size(); i++) {
		if (equalsIgnoreCase(refFields[i], "speechfile"))
			ref += "#" + audioSource;
		else if (equalsIgnoreCase(refFields[i], "reference word sequence"))
			ref += "#" + refSent;
		else if (equalsIgnoreCase(refFields[i], "topic"))
			ref += "#" + refTopic;
		else if (equalsIgnoreCase(refFields[i], ";slot names"))
			ref += "#" + refSlotNames;
		else if (equalsIgnoreCase(refFields[i], ";slot values"))
			ref += "#" + refSlotValues;
		else
			ref += "#" + refOtherFields[refFields[i]];
	}
	return ref;
}

std::string SRNLUReference::serializeJSON(void)
{
	std::string jsonString = "\"reference\":{";

	jsonString += "\"audio\":\"" + replaceAll(audioSource, "\\", "\\\\") + "\"";
	if (refSent.length() > 0)
		jsonString += ",\"trans\":\"" + refSent + "\"";
	if (refTopic.length() > 0)
		jsonString += ",\"topic\":\"" + refTopic + "\"";
	
	if (refSlots.size() > 0) {
		jsonString += ",\"slots\":[";
		for (std::map<std::string, std::string>::iterator iteSlot = refSlots.begin(); iteSlot != refSlots.end(); iteSlot++)
		{
			jsonString += (iteSlot==refSlots.begin()) ? "{" : ",{";
			jsonString += "\"slotname\":\"" + iteSlot->first + "\",";
			jsonString += "\"slotvalue\":\"" + iteSlot->second + "\"}";
		}
		jsonString += "]";
	}

	if (refOtherFields.size() > 0) {
		jsonString += ",\"otherFields\":{";
		for (std::map<std::string, std::string>::iterator iteInfo = refOtherFields.begin(); iteInfo != refOtherFields.end(); iteInfo++)
		{
			jsonString += (iteInfo==refOtherFields.begin()) ? "" : ",";
			jsonString += "\"" + iteInfo->first + "\":";
			jsonString += "\"" + iteInfo->second + "\"";
		}
		jsonString += "}";
	}

	jsonString += "}";
	return jsonString;
}

void SRNLUReference::clear(void)
{
	audioSource = "";
	refSent = "";
	refTopic = "";
	refSlots.clear();
	refOtherFields.clear();
}

SRNLUBatchTester* SRNLUBatchTester::getInstance()
{
	if (!m_pInstance)
		m_pInstance = new SRNLUBatchTester();
	return m_pInstance;
}

void SRNLUBatchTester::create()
{
	if (!m_pInstance)
		m_pInstance = new SRNLUBatchTester();
}

void SRNLUBatchTester::release()
{
	if (m_pInstance)
		delete m_pInstance;
	m_pInstance = NULL;
}

void SRNLUBatchTester::init(std::string hrlName)
{
	hrlFile.openFile(hrlName.c_str());
	std::string refline = "";
	while (hrlFile.getLine(m_currentLine)) {
		if (!startsWith(m_currentLine, "#"))
			break;
		trim(m_currentLine);
		if (startsWith(m_currentLine, "#ref#")) {
			refline = m_currentLine + "#number of hypotheses#result type";
			splitString(m_currentLine.substr(5, m_currentLine.length()-5), "#", m_fields);
		}
	}

	std::string outputFileName = hrlName + ".sr.res";
	outputFile.openOutFile(outputFileName.c_str());
	outputFile.writeLine("#head;res;2.0;utf-8#soundFiledir#hrl filepath");
	outputFile.writeLine(refline.c_str());
	outputFile.writeLine("#hyp#rank#ctx#;hypothesis#confidence#score#lmScore#;terminal confidences#;terminal lmScores");
	outputFile.writeLine("#classres#classifier name#topic#score");
	outputFile.writeLine("#interpretation#rank#score#;slot names#;slot values#;slot scores");
	outputFile.writeLine("head#folderdummy#filedummy");
}

bool SRNLUBatchTester::getNextTestCase(SRNLUReference &ref)
{
	while (!startsWith(m_currentLine, "ref#")) {
		if (!hrlFile.getLine(m_currentLine)) {
			return false;
		}
	}
	ref.clear();
	std::vector<std::string> values;
	splitString(m_currentLine.substr(4, m_currentLine.length()-4), "#", values);
	if (values.size() == m_fields.size()) {
		std::vector<std::string> slotnames;
		std::vector<std::string> slotvalues;
		for (int i=0; i<(int)values.size(); i++) {
			if (equalsIgnoreCase(m_fields[i], "speechfile"))
				ref.audioSource = values[i];
			else if (equalsIgnoreCase(m_fields[i], "reference word sequence"))
				ref.refSent = values[i];
			else if (equalsIgnoreCase(m_fields[i], "topic"))
				ref.refTopic = values[i];
			else if (equalsIgnoreCase(m_fields[i], ";slot names"))
				splitString(values[i], ";", slotnames);
			else if (equalsIgnoreCase(m_fields[i], ";slot values"))
				splitString(values[i], ";", slotvalues);
			else
				ref.refOtherFields[m_fields[i]] = values[i];
		}
		if (slotnames.size() > 0 && slotnames.size() == slotvalues.size()) {
			for (int i=0; i<(int)slotnames.size(); i++)
				ref.refSlots[slotnames[i]] = slotvalues[i];
		}
	}
	hrlFile.getLine(m_currentLine);
	return true;
}

void SRNLUBatchTester::logTestResult(SRNLUResult result)
{
	std::string strResult = result.serializeVoConHRL(m_fields);
	if (endsWith(strResult, "\n"))
		strResult = strResult.substr(0, strResult.length()-1);
	outputFile.writeLine(strResult.c_str());
}

SRNLUBatchTester::SRNLUBatchTester(void)
{
	m_testMode = SR_NLU_BATCH_DISABLE;
	m_currentLine = "";
}

SRNLUBatchTester::~SRNLUBatchTester(void)
{
}
